﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using agilecards.Model;
using System.Collections.Specialized;
using System.Collections;
using System.Windows.Threading;

namespace agilecards
{
    public partial class Page : UserControl, IMouseEventSource
    {
        public Page(ICardCollection cardCollection, ICardCollectionPersistor persistor)
        {
            InitializeComponent();
            _persistor = persistor;
            SetupNotificationTimer();

            InitForCollection(cardCollection);
        }

        private void InitForCollection(ICardCollection cardCollection)
        {
            if (_cardCollection != null)
            {
                _cardCollection.Cards.CollectionChanged -= new NotifyCollectionChangedEventHandler(Cards_CollectionChanged);
            }

            _cardCollection = cardCollection;
            _cardCollection.Cards.CollectionChanged += new NotifyCollectionChangedEventHandler(Cards_CollectionChanged);

            _collectionName.DataContext = _cardCollection;
            _collectionSum.DataContext = _cardCollection;
            _cardsSummaryListBox.ItemsSource = _cardCollection.Cards;

            SetBoardIdMessage(cardCollection);

            CreateControlsForCards(cardCollection.Cards);

            CreateDragManager();

            SetupNotificationTimer();
        }

        void SetBoardIdMessage(ICardCollection cardCollection)
        {
            string boardId = (cardCollection.Id != null) ? cardCollection.Id : "<not saved>";
            _txtBoardIdMessage.Text = "Board: " + boardId;
        }

        private void CreateDragManager()
        {
            CardDragManager dragManager = new CardDragManager(this, _canvas);
        }

        private void SetupNotificationTimer()
        {
            _notificationTimer = new DispatcherTimer();
            _notificationTimer.Interval = new TimeSpan(0, 0, 2);
            _notificationTimer.Tick += new EventHandler(notificationTimer_Tick);
        }

        void notificationTimer_Tick(object sender, EventArgs e)
        {
            _txtNotificationMessage.Text = "Idle";
            _notificationTimer.Stop();
        }

        public void RegisterMessageNotifier(INotifier notifier)
        {
            notifier.NotifyOccured += new EventHandler<NotifyOccuredEventArgs>(notifier_NotifyOccured);
        }

        void notifier_NotifyOccured(object sender, NotifyOccuredEventArgs e)
        {
            _txtNotificationMessage.Text = e.Message;
            _notificationTimer.Start();
        }

        void Cards_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            IList newCards = e.NewItems;
            CreateControlsForCards(newCards);
        }

        private void CreateControlsForCards(IList newCards)
        {
            foreach (Card item in newCards)
            {
                CardControl ctrl = new CardControl();
                ctrl.DataContext = item;
                _canvas.Children.Add(ctrl);
            }
        }

        void ctrl_MovingStarted(object sender, EventArgs e)
        {
            SendAllChildrenToBack();
            BringToFront((Control)sender);
        }

        private void BringToFront(Control control)
        {
            Canvas.SetZIndex(control, 1);
        }

        private void SendAllChildrenToBack()
        {
            foreach (Control control in _canvas.Children)
            {
                Canvas.SetZIndex(control, 0);
            }
        }

        private void _canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            OnMouseDown(new CanvasMouseEventArgs(e.GetPosition(null)));
            HandleMouseDown(e);
        }

        private void HandleMouseDown(MouseButtonEventArgs e)
        {
            if (HasHitSomething(e)) return;

            AddCard(e);
        }

        private bool HasHitSomething(MouseButtonEventArgs e)
        {
            return VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), _canvas).Count() > 1;
        }

        void AddCard(MouseButtonEventArgs e)
        {
            Point position = e.GetPosition(_canvas);
            _cardCollection.AddCard(position);
        }


        #region IMouseEventSource Members

        public event EventHandler<CanvasMouseEventArgs> MouseDown;

        public event EventHandler<CanvasMouseEventArgs> MouseUp;

        public new event EventHandler<CanvasMouseEventArgs> MouseMove;

        #endregion

        private void _canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            OnMouseUp(new CanvasMouseEventArgs(e.GetPosition(null)));
        }

        private void _canvas_MouseMove(object sender, MouseEventArgs e)
        {
            OnMouseMove(new CanvasMouseEventArgs(e.GetPosition(null)));
        }

        protected void OnMouseUp(CanvasMouseEventArgs e)
        {
            if (this.MouseUp != null)
            {
                MouseUp(this, e);
            }
        }
        protected void OnMouseDown(CanvasMouseEventArgs e)
        {
            if (this.MouseDown != null)
            {
                MouseDown(this, e);
            }
        }
        protected void OnMouseMove(CanvasMouseEventArgs e)
        {
            if (this.MouseMove != null)
            {
                MouseMove(this, e);
            }
        }


        private void _btnLoad_Click(object sender, RoutedEventArgs e)
        {
            LoadBoard();

        }

        private void LoadBoard()
        {
            //TODO Of course this will soon be in a controller, sorry...
            string boardId = AskForBoardId();
            ICardCollection collection = _persistor.Load(boardId);
            if (collection == null)
            {
                DisplayNonExistingBoardMessage(boardId);
            }
            else
            {
                InitForCollection(collection);
            }
        }

        private void DisplayNonExistingBoardMessage(string boardId)
        {
            MessageBox.Show("Board not found: " + boardId);
        }

        private string AskForBoardId()
        {
            return _txtBoardIdToLoad.Text;
        }

        private void _btnSave_Click(object sender, RoutedEventArgs e)
        {
            SaveBoard();
        }

        private void SaveBoard()
        {
            //TODO this too in a controller...
            EnsureCollectionHasId(_cardCollection);
            _persistor.Save(_cardCollection);
        }

        private void EnsureCollectionHasId(ICardCollection _cardCollection)
        {
            if (!string.IsNullOrEmpty(_cardCollection.Id)) return;

            _cardCollection.Id = Guid.NewGuid().ToString();
            MessageBox.Show(string.Format(
                "Your board has been saved with Id: {0}\nPlease copy this Id to be able to retrieve the board in the future.",
                _cardCollection.Id));
        }

        
        DispatcherTimer _notificationTimer;
        ICardCollectionPersistor _persistor;
        ICardCollection _cardCollection;
    }
}
